package com.myk.game.gobangchess.ai.symmetric;

import java.util.List;
import java.util.Random;

/**
 * 文件名: TrendScorer.java
 * 类名: TrendScorer
 * 功能: 提供局面趋势打分功能。
 */
public class TrendScorer {


    private static final Random random = new Random();

    /**
     * 计算给定玩家的棋块分数。
     * 此函数为私有辅助函数，仅计算对称棋块的分数。
     *
     * @param playerColor   玩家颜色 (1:黑, -1:白)。
     * @param state         当前游戏状态。
     * @param coefficients  包含所有打分参数的数组。
     * @return 该玩家的总棋块分数。
     */
    private static double calculatePlayerBlockScore(int playerColor, GameState state, double[] coefficients) {
        double totalBlockScore = 0.0;

        // 获取该玩家的所有棋块信息
        List<List<int[]>> blocks = state.allBlocks.get(playerColor);
        List<Boolean> symmetries = state.blockSymmetries.get(playerColor);
        List<Integer> sizes = state.blockSizes.get(playerColor);

        // 如果该玩家没有棋块，直接返回0分
        if (blocks == null || blocks.isEmpty()) {
            return 0.0;
        }

        for (int i = 0; i < blocks.size(); i++) {
            // 只对对称的棋块进行计分
            if (symmetries.get(i)) {
                int size = sizes.get(i);
                double scoreForThisBlock = 0.0;

                if (size >= 1 && size <= 11) {
                    // 对应参数c5到c15，在数组中索引为4到14
                    // size 1 -> c5 -> index 4
                    // size 11 -> c15 -> index 14
                    // 索引 = size + 3
                    scoreForThisBlock = -coefficients[size + 3];
                } else if (size > 11) {
                    // 对应参数c15和c16，在数组中索引为14和15
                    scoreForThisBlock = -(coefficients[14] + coefficients[15] * (size - 11));
                }
                totalBlockScore += scoreForThisBlock;
            }
        }
        return totalBlockScore;
    }

    /**
     * 局面趋势打分函数。
     * 在某玩家完成回合后，从该玩家视角对局面进行打分。分数越高，代表局面越有利。
     * 此函数为只读，不修改GameState对象。
     *
     * @param state         当前完整的游戏状态 (GameState对象)。
     * @param playerColor   刚刚完成回合的玩家颜色 (1:黑, -1:白)。
     * @param coefficients  一个包含17个double类型元素的数组，定义了所有打分权重。
     *                      - coefficients[0-3]: 对应c1-c4，用于均匀度计算。
     *                      - coefficients[4-14]: 对应c5-c15，用于大小为1-11的棋块扣分。
     *                      - coefficients[15]: 对应c16，用于大小>11的棋块的额外扣分系数。
     *                      - coefficients[16]: 对应c17，用于随机扰动。
     * @return double类型的分数，评估局面对`playerColor`的有利程度。
     */
    public static double calculateTrendScore(GameState state, int playerColor, double[] coefficients) {
        // 1. 均匀度分数
        double[] uniformityCoeffs = {coefficients[0], coefficients[1], coefficients[2], coefficients[3]};
        double[] uniformityScores = UniformityScorer.calculateUniformity(state.board, uniformityCoeffs);
        
        // 假设UniformityScorer返回的数组中，[0]为黑棋分，[1]为白棋分
        double myUniformityScore = (playerColor == 1) ? uniformityScores[0] : uniformityScores[1];
        double opponentUniformityScore = (playerColor == 1) ? uniformityScores[1] : uniformityScores[0];
        double uniformityTotalScore = myUniformityScore - opponentUniformityScore;

        // 2. 棋块分数
        int opponentColor = -playerColor;
        double myBlockScore = calculatePlayerBlockScore(playerColor, state, coefficients);
        double opponentBlockScore = calculatePlayerBlockScore(opponentColor, state, coefficients);
        double blockTotalScore = myBlockScore - opponentBlockScore;

        // 3. 随机扰动
        // coefficients[16] 是 c17
        double randomComponent = coefficients[16] * random.nextGaussian();

        // 4. 计算总分
        double finalScore = uniformityTotalScore + blockTotalScore + randomComponent;

  
        // System.out.println("--- Trend Score Calculation (Perspective: " + (playerColor == 1 ? "Black" : "White") + ") ---");
        // System.out.printf("Uniformity Score (My): %.4f\n", myUniformityScore);
        // System.out.printf("Uniformity Score (Opponent): %.4f\n", opponentUniformityScore);
        // System.out.printf("Uniformity Total: %.4f\n", uniformityTotalScore);
        // System.out.println("------------------------------------");
        // System.out.printf("Block Score (My): %.4f\n", myBlockScore);
        // System.out.printf("Block Score (Opponent): %.4f\n", opponentBlockScore);
        // System.out.printf("Block Total: %.4f\n", blockTotalScore);
        // System.out.println("------------------------------------");
        // System.out.printf("Random Component: %.4f\n", randomComponent);
        // System.out.printf("Final Trend Score: %.4f\n", finalScore);
        // System.out.println("------------------------------------");


        return finalScore;
    }

    /**
     * 用于功能验证的 main 函数。
     */
    public static void main(String[] args) {
        // 1. 定义一个显式的15x15棋盘矩阵用于测试
        int[][] board = {
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, // 黑方大小为2的对称棋块
            {0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 白方大小为1的棋块
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0,-1,-1,-1, 0, 0, 0, 0}, // 白方大小为3的对称棋块
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0,-1,-1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
        };

        // 2. 打印棋盘以供参考
        System.out.println("Initial Board for Testing:");
        BoardPrinter.printBoardWithIndices(board);
        System.out.println();

        // 3. 生成GameState对象
        // 假设黑方(1)刚刚完成了回合
        GameState state = GameStateGenerator.getGameState(board);
        state.currentPlayer = -1; // 下一回合是白方
        
        // 4. 定义打分系数 (17个)
        // c1-c4: 均匀度系数
        // c5-c15: 棋块大小1-11的扣分
        // c16: 棋块大小>11的额外扣分系数
        // c17: 随机扰动系数
        double[] coefficients = {
            // c1-c4 (Uniformity)
            1.0, 1.0, 1.0, 1.0,
            // c5-c15 (Block size penalties for size 1-11)
            5.0,  // c5 (size 1)
            1.0,  // c6 (size 2)
            2.0,  // c7 (size 3)
            6.0,  // c8 (size 4)
            6.0,  // c9 (size 5)
            7.0,  // c10 (size 6)
            8.0,  // c11 (size 7)
            9.0,  // c12 (size 8)
            11.0, // c13 (size 9)
            13.0, // c14 (size 10)
            15.0, // c15 (size 11)
            // c16 (Extra penalty for size > 11)
            1.5,
            // c17 (Randomness factor)
            0.01
        };

        // 5. 调用打分函数并打印结果
        int playerWhoJustMoved = 1; // 假设是黑方(1)刚走完
        System.out.println("Calculating trend score from Black's (1) perspective...");
        double score = calculateTrendScore(state, playerWhoJustMoved, coefficients);

        System.out.println("\n================== FINAL RESULT ==================");
        System.out.println("Board State Analyzed from Player " + playerWhoJustMoved + "'s perspective.");
        System.out.printf("Final Trend Score: %.4f\n", score);
        System.out.println("================================================");
        
        // 预期棋块分数计算:
        // 我方(黑): 1个大小为4的对称块(假设(1,1),(1,2),(2,1),(2,2)构成一个对称块)。扣分 -c8 = -6.0
        // 对方(白): 1个大小为1的块，1个大小为3的对称块。扣分 -c5 + (-c7) = -5.0 + (-2.0) = -7.0
        // 棋块总分 = (-6.0) - (-7.0) = 1.0
        // 最终分数会是 1.0 + (均匀度分差) + (随机数)
    }
}